package test.generic;

import java.util.function.Function;

/**
 * 体验泛型方法：当方法操作的引用数据类型不确定的时候，可以将泛型定义在方法上
 *
 * 方法体上的 <T> 的作用是告诉编译器，形式参数中的T是一个占位符，是要根据实际参数的类型来设置的
 */
public class GenericMethods{

    public <T> T testMethod(T x){
        return x ;
    }

    /**
     * 静态方法上的泛型：静态方法无法访问类上定义的泛型。如果静态方法操作的引用数据类型不确定的时候，必须要将泛型定义在方法上
     */
    public static <A> void function(A t) {
        System.out.println("function:"+t);
    }

    /**
     * 规定T必须继承某个类
     *
     * @param tClass
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T extends Number> T cloneWithoutUserCache(Class<T> tClass) throws Exception{
        T t = tClass.newInstance();
        return t ;
    }

    //<R,T>的作用是告诉编译器，形式参数中的R和T是一个占位符，，是要根据实际参数的类型来设置的
    // Function《T，R》是jdk1.8中，java.util.function包里的接口类，他有一个方法R apply(T t);
    // <? extends R> 表示的是类型的上限是R（即R或R的子类，其实和直接传R效果是一样的）
    // <? super T> 表示的是类型的下限是T（即T或T的父类）
    public <R,T> R myMap(Function<? super T,? extends R> func, T t){
       return func.apply(t);
    }

    public static void main(String[] args) {
        GenericMethods gm = new GenericMethods();
        System.out.println(gm.testMethod(99).getClass().getName()); //结果：java.lang.Integer
        System.out.println(gm.testMethod("掌上洪城").getClass().getName());//结果：java.lang.String
        System.out.println(gm.testMethod(new Integer(99)).getClass().getName()); //结果：java.lang.Integer
        System.out.println(gm.testMethod(18.88).getClass().getName());//结果：java.lang.Double
        System.out.println(gm.testMethod('a').getClass().getName());//结果：java.lang.Character
        System.out.println(gm.testMethod(gm).getClass().getName());//结果：test.generic.GenericMethods

        Function<String,Person> func = s -> {
            System.out.println(s);
            return new Student();
        };
        //String实现了CharSequence，满足了<? super T>
        Person person = gm.myMap(func,"测试map方法");
        System.out.println(person.getClass()); //class test.generic.GenericMethods$Student
    }

    static class Person{

    }
    static class Student extends Person{

    }
}
